/**
 * @author raymondlo
 */

var AACallFuncND = exports.AACallFuncND = Core.Class.subclass({
/** @lends Animation.AACallFuncND.prototype */    
	classname: 'AACallFuncND',
	
	/**
	 * @class An action which calls a function.
	 * Calls a callback with the function as the first argument and a parameter as the second argument.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var func = new Animation.AACallFuncND(function(param) { alert(param); }, 'abc'); 
	 * node.runAction(func);
	 *
	 * @constructs The default constructor.
	 * @augments Core.Class
	 * @param {Function} callback The callback function to call.
	 * @param {Object} param The paramater (if any) for the callback function.
	 */
    initialize: function(callback, param)
    {
		this.callback = callback;
		this.param = param;
		this.node = null;
		this.executed = false;
    },
	
	/** 
     * Starts the action
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	startAction: function(node) {
		this.executed = false;
		this.node = node;
	},
	
	/** 
     * Method to be performed on every tick
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	update: function(node) {
		if (!this.isDone()) {
			this.executed = true;
			this.callback(this.node, this.param);
		}
	},
	
	/** 
     * Creates a clone of the action
     */
	clone: function() {
		return new AACallFuncND(this.callback, this.param);
	},
	
	/** 
     * Checks if the action has been completed
     * @param {AANode.Class} node The node to run the action on
     * @returns {Boolean} The action finished executing
     */
	isDone: function() {
		return this.executed;
	},
});


var AADelayTime = exports.AADelayTime = Core.Class.subclass({
/** @lends Animation.AADelayTime.prototype */    
	classname: 'AADelayTime',
	
	/**
	 * @class An action that delays for a certain amount of time.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var delay = new Animation.AADelayTime(2.0);
	 * var func = new Animation.AACallFuncND(function(param) { alert(param); }, 'abc');
	 * var sequence = new AASequence(delay, func);
	 * node.runAction(sequence); 
	 *
	 * @param {Float} duration The duration in miliseconds to delay
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(duration)
    {
		this.elapsed = 0;
		this.duration = duration * 1000;
    },
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
	},
	
	/**
	 * @private
	 */
	update:function(t, node) {
		this.elapsed += t;
	},
	
	clone: function() {
		return new AADelayTime(this.duration/1000);
	},
	
	isDone: function() {
		return (this.elapsed >= this.duration);
	},
});


var AAEaseIn = exports.AAEaseIn = Core.Class.subclass({
/** @lends Animation.AAEaseIn.prototype */
    classname: 'AAEaseIn',
	
	/**
	 * @class An action that eases in with a rate parameter.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var move = new Animation.AAMoveTo(new Core.Point(250,400), 2.0);
	 * var ease = new Animation.AAEaseIn(move, 2);  
	 * node.runAction(ease);
	 *
	 * @param {Core.Class} action The action in which to ease.
	 * @param {Float} rate The rate of the ease.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(action, rate)
    {
		this.action = action;
		this.rate = rate;
		this.elapsed = 0;
    },
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.action.startAction(node);
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		if (!this.isDone()) {
			this.elapsed += t;
			this.action.elapsed = 0; //stupid hack way cause i messed up
			var a = Math.pow(this.elapsed/this.action.duration, this.rate) * this.action.duration;
			this.action.update(a, node);
		}
	},
	
	clone: function() {
		return new AAEaseIn(this.action.clone(), this.rate);
	},
	
	isDone: function() {
		return this.elapsed >= this.action.duration;
	},
});


var AAEaseOut = exports.AAEaseOut = Core.Class.subclass({
/** @lends Animation.AAEaseOut.prototype */
    classname: 'AAEaseOut',
	
	/**
	 * @class An action that eases out with a rate parameter.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var move = new Animation.AAMoveTo(new Core.Point(250,400), 2.0);
	 * var ease = new Animation.AAEaseOut(move, 2);  
	 * node.runAction(ease);
	 *
	 * @param {Core.Class} action The action in which to ease.
	 * @param {Float} rate The rate of the ease.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
     initialize: function(action, rate)
    {
		this.action = action;
		this.rate = rate;
		this.elapsed = 0;
    },
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.action.startAction(node);
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		if (!this.isDone()) {
			this.elapsed += t;
			this.action.elapsed = 0; //stupid hack way cause i messed up
			var a = Math.pow(this.elapsed/this.action.duration, 1/this.rate) * this.action.duration;
			this.action.update(a, node);
		}
	},
	
	clone: function() {
		return new AAEaseOut(this.action.clone(), this.rate);
	},
	
	isDone: function() {
		return this.elapsed >= this.action.duration;
	},
});

var AAEaseInOut = exports.AAEaseInOut = Core.Class.subclass({
/** @lends Animation.AAEaseInOut.prototype */
    classname: 'AAEaseInOut',
	
    initialize: function()
    {

    },
});


var AAFadeTo = exports.AAFadeTo = Core.Class.subclass({
/** @lends Animation.AAFadeTo.prototype */	
	classname: 'AAFadeTo',    
		
	/**
	 * @class An action that fades a node.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fade = new Animation.AAFadeTo(0.5, 3.0);
	 * node.runAction(fade);
	 *
	 * @param {Float} value The opacity in which to fade to.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(value, duration) { 
		this.startAlpha = 0;
		this.endAlpha = value;
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = 0;
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startAlpha = node.getAlpha();
		this.delta = this.endAlpha - this.startAlpha;
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		this.elapsed += t;
		if (this.isDone()) {
			node.setAlpha(this.endAlpha);
		} else {
			var newAlpha = this.startAlpha + this.delta * (this.elapsed / this.duration);
			node.setAlpha(newAlpha);
		}
	},
	
	clone: function() {
		return new AAFadeTo(this.endAlpha, this.duration/1000);
	},
	
	isDone: function() {
		return (this.elapsed >= this.duration);
	},
});


var AAFadeIn = exports.AAFadeIn = AAFadeTo.subclass({
/** @lends Animation.AAFadeIn.prototype */
    classname: 'AAFadeIn',
	
	/**
	 * @class An action that fully fades in a node.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fade = new Animation.AAFadeIn(3.0);
	 * node.runAction(fade);
	 *
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Animation.AAFadeTo
	 */
    initialize: function($super, duration) {
		$super(1.0,duration);
	},
	
	clone: function() {
		return new AAFadeIn(this.duration/1000);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startAlpha = node.getAlpha();
		this.delta = this.endAlpha - this.startAlpha;
	},
});


var AAFadeOut = exports.AAFadeOut = AAFadeTo.subclass({
/** @lends Animation.AAFadeOut.prototype */
	classname: 'AAFadeOut',

	/**
	 * @class An action that fully fades out a node.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fade = new Animation.AAFadeOut(3.0);
	 * node.runAction(fade);
	 *
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Animation.AAFadeTo
	 */    
    initialize: function($super, duration) { 
		$super(0,duration);
	},
	
	clone: function() {
		return new AAFadeOut(this.duration/1000);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startAlpha = node.getAlpha();
		this.delta = this.endAlpha - this.startAlpha;
	},
});


var AAMoveTo = exports.AAMoveTo = Core.Class.subclass({
/** @lends Animation.AAMoveTo.prototype */
    classname: 'AAMoveTo',
	
	/**
	 * @class An action that moves a node to a specific location.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var move = new Animation.AAMoveTo(new Core.Point(250,400), 2.0);
	 * node.runAction(move);
	 *
	 * @param {Core.Point} position The position to move to.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
	initialize: function(position, duration) { 
		this.startPosition = new Core.Point(0,0);
		this.endPosition = position;
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = new Core.Point(0,0);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startPosition = node.getPosition().clone();
		this.delta.setAll(this.endPosition.getX() - this.startPosition.getX(), this.endPosition.getY() - this.startPosition.getY());
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		this.elapsed += t;
		if (this.isDone()) {
			node.setPosition(this.endPosition);
		} else {
			var newX = this.startPosition.getX() + (this.delta.getX() * (this.elapsed / this.duration));
			var newY = this.startPosition.getY() + (this.delta.getY() * (this.elapsed / this.duration));
			
			node.setPosition(newX, newY);
		}
	},
	
	clone: function() {
		return new AAMoveTo(this.endPosition.clone(), this.duration/1000);
	},
	
	isDone: function() {
		return (this.elapsed >= this.duration);
	},
});


var AAMoveBy = exports.AAMoveBy = AAMoveTo.subclass({
/** @lends Animation.AAMoveBy.prototype */
   classname: 'AAMoveBy',
   /**
	 * @class An action that moves a node by a certain amount.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var move = new Animation.AAMoveBy(new Core.Point(50,40), 2.0);
	 * node.runAction(move);
	 *
	 * @param {Core.Point} position The position to move by.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Animation.AAMoveTo
	 */
	initialize: function(position, duration) { 
		this.startPosition = new Core.Point(0,0);
		this.endPosition = new Core.Point(0,0);
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = position;
	},
	
	clone: function() {
		return new AAMoveBy(this.delta.clone(), this.duration/1000);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startPosition = node.getPosition().clone();
		this.endPosition.setAll(this.startPosition.getX() + this.delta.getX(), this.startPosition.getY() + this.delta.getY());
	},
	
});


var AARepeat = exports.AARepeat = Core.Class.subclass({
/** @lends Animation.AARepeat.prototype */
    classname: 'AARepeat',
	/**
	 * @class An action that repeats another action a certain amount of times.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fadein = new Animation.AAFadeIn(0.5);
	 * var fadeout = new Animation.AAFadeOut(0.5);
	 * var pause = new Animation.AADelayTime(2.0);
	 * var sequence = new Animation.AASequence(fadeout, pause, fadein);
	 * var repeat = new Animation.AARepeat(sequence, 10);
	 * node.runAction(repeat);
	 *
	 * @param {Core.Class} action The action to repeat.
	 * @param {Integer} times The amount of times to repeat.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(action, times)
    {
		this.action = action;
		this.times = times;
		this.iteration = 0;
    },
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.iteration = 1;
		this.action.startAction(node);
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		if (!this.isDone()) {
			if (this.action.isDone()) {
				//start next iteration
				this.iteration++;
				this.action = this.action.clone();
				this.action.startAction(node);
			} else {
				this.action.update(t, node);
			}
		}
	},
	
	clone: function() {
		return new AARepeat(this.action.clone(), this.times);
	},
	
	isDone: function() {
		return this.iteration > this.times;
	},
});


var AARepeatForever = exports.AARepeatForever = AARepeat.subclass({
/** @lends Animation.AARepeatForever.prototype */
    classname: 'AARepeatForever',
	/**
	 * @class An action that repeats another action forever.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fadein = new Animation.AAFadeIn(0.5);
	 * var fadeout = new Animation.AAFadeOut(0.5);
	 * var pause = new Animation.AADelayTime(2.0);
	 * var sequence = new Animation.AASequence(fadeout, pause, fadein);
	 * var repeat = new Animation.AARepeatForever(sequence);
	 * node.runAction(repeat);
	 *
	 * @param {Core.Class} action The action to repeat.
	 * @constructs The default constructor.
	 * @augments Animation.AARepeat
	 */
    initialize: function($super, action) {
		$super(action,-1);
	},
	
	clone: function() {
		return new AARepeatForever(this.action.clone());
	},
	
	isDone: function() {
		return false;
	},
});


var AARotateTo = exports.AARotateTo = Core.Class.subclass({
/** @lends Animation.AARotateTo.prototype */
  	classname: 'AARotateTo',
	/**
	 * @class An action that rotates a node to a certain angle.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var rotate = new Animation.AARotateTo(180, 4.0);
	 * node.runAction(rotate);
	 *
	 * @param {Float} rotation The angle to rotate to.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(rotation, duration) { 
		this.startRotation = 0;
		this.endRotation = rotation;
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = 0;
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startRotation = node.getRotation();
		this.delta = this.endRotation - this.startRotation;
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		this.elapsed += t;
		if (this.isDone()) {
			node.setRotation(this.endRotation);
		} else {
			var newRotation = this.startRotation + (this.delta * (this.elapsed / this.duration));
			
			node.setRotation(newRotation);
		}
	},
	
	clone: function() {
		return new AARotateTo(this.endRotation, this.duration/1000);
	},
	
	isDone: function() {
		return (this.elapsed >= this.duration);
	},
});


var AARotateBy = exports.AARotateBy = AARotateTo.subclass({
/** @lends Animation.AARotateBy.prototype */
  	classname: 'AARotateBy',
	/**
	 * @class An action that rotates a node by a certain angle.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var rotate = new Animation.AARotateBy(80, 4.0);
	 * node.runAction(rotate);
	 *
	 * @param {Float} rotation The angle to rotate by.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
	initialize: function(rotation, duration) { 
		this.startRotation = 0;
		this.endRotation = 0;
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = rotation;
	},
	
	clone: function() {
		return new AARotateBy(this.delta, this.duration/1000);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startRotation = node.getRotation();
		this.endRotation = this.startRotation + this.delta;
	},
});


var AAScaleTo = exports.AAScaleTo = Core.Class.subclass({
/** @lends Animation.AAScaleTo.prototype */
    classname: 'AAScaleTo',
	/**
	 * @class An action that scales a node to a certain percentage.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var scale = new Animation.AAScaleTo(new Core.Vector(0.5,0.5), 2.0);
	 * node.runAction(scale);
	 *
	 * @param {Core.Vector} scale The size to scale to.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(scale, duration) { 
		this.startScale = new Core.Vector(0,0);
		this.endScale = scale;
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = new Core.Vector(0,0);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startScale = node.getScale().clone();
		this.delta.setAll(this.endScale.getX() - this.startScale.getX(), this.endScale.getY() - this.startScale.getY());
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		this.elapsed += t;
		if (this.isDone()) {
			node.setScale(this.endScale);
		} else {
			var newX = this.startScale.getX() + (this.delta.getX() * (this.elapsed / this.duration));
			var newY = this.startScale.getY() + (this.delta.getY() * (this.elapsed / this.duration));
			
			node.setScale(newX, newY);
		}
	},
	
	clone: function() {
		return new AAScaleTo(this.endScale.clone(), this.duration/1000);
	},
	
	isDone: function() {
		return (this.elapsed >= this.duration);
	},
});


var AAScaleBy = exports.AAScaleBy = AAScaleTo.subclass({
/** @lends Animation.AAScaleBy.prototype */
    classname: 'AAScaleBy',
	/**
	 * @class An action that scales a node by a certain percentage.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var scale = new Animation.AAScaleBy(new Core.Vector(0.5,0.5), 2.0);
	 * node.runAction(scale);
	 *
	 * @param {Core.Vector} scale The size to scale by.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Animation.AAScaleTo
	 */
    initialize: function(scale, duration) { 
		this.startScale = new Core.Vector(0,0);
		this.endScale = new Core.Vector(0,0);
		this.elapsed = 0;
		this.duration = duration * 1000;
		this.delta = scale;
	},
	
	clone: function() {
		return new AAScaleBy(this.delta.clone(), this.duration/1000);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startScale = node.getScale().clone();
		this.endScale.setAll(this.startScale.getX() + this.delta.getX(), this.startScale.getY() + this.delta.getY());
	},
});


var AABezier = exports.AABezier = Core.Class.subclass({
/** @lends Animation.AABezier.prototype */
	classname: 'AABezier',
	/**
	 * @class A class that holds the bezier curve values.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
	initialize: function() {
		this.endPosition = new Core.Point(0,0);
		this.controlPoint1 = new Core.Point(0,0);
		this.controlPoint2 = new Core.Point(0,0);
	},
	
	clone: function() {
		var newBezier = new AABezier();
		newBezier.endPosition = this.endPosition.clone();
		newBezier.controlPoint1 = this.controlPoint1.clone();
		newBezier.controlPoint2 = this.controlPoint2.clone(); 
		return newBezier;
	},
});


var AABezierBy = exports.AABezierBy = Core.Class.subclass({
/** @lends Animation.AABezierBy.prototype */
    classname: 'AABezierBy',
	/**
	 * @class An action that moves a node on a bezier curve.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var bezier = new Animation.AABezier();
	 * bezier.controlPoint1.setAll(-100,0);
	 * bezier.controlPoint2.setAll(-150,150);
	 * bezier.endPosition.setAll(-125,200);
	 * var bezierBy = new Animation.AABezierBy(bezier,3.0);
	 * node.runAction(bezierBy);
	 *
	 * @param {AABezier.Class} bezier The bezier values for the curve.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function(bezier, duration) { 
		this.startPosition = new Core.Point(0,0);
		this.endPosition = new Core.Point(0,0);
		this.bezier = bezier;
		this.bezier2 = bezier.clone(); //incase original bezier is needed.  all calculations are done with the clone.
		this.elapsed = 0;
		this.duration = duration * 1000;
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startPosition = node.getPosition().clone();
		this.endPosition.setAll(this.startPosition.getX() + this.bezier2.endPosition.getX(), this.startPosition.getY() + this.bezier2.endPosition.getY());
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		this.elapsed += t;
		if (this.isDone()) {
			node.setPosition(this.endPosition);
		} else {
			xa = 0;
			xb = this.bezier2.controlPoint1.getX();
			xc = this.bezier2.controlPoint2.getX();
			xd = this.bezier2.endPosition.getX();
			
			ya = 0;
			yb = this.bezier2.controlPoint1.getY();
			yc = this.bezier2.controlPoint2.getY();
			yd = this.bezier2.endPosition.getY(); 
			
			var x = this.bezierat(xa, xb, xc, xd, this.elapsed/this.duration);
			var y = this.bezierat(ya, yb, yc, yd, this.elapsed/this.duration);
			
			node.setPosition(this.startPosition.getX() + x, this.startPosition.getY() + y);
		}
	},
	
	/**
	 * @private
	 */
	bezierat: function(a, b, c, d, t) {
		return 	(Math.pow(1-t,3) * a +
				3 * t * Math.pow(1-t,2) * b +
				3 * Math.pow(t,2) * (1-t) * c +
				Math.pow(t,3) * d);
	},
	
	clone: function() {
		return new AABezierBy(this.bezier.clone(), this.duration/1000);
	},
	
	isDone: function() {
		return (this.elapsed >= this.duration);
	},
});


var AABezierTo = exports.AABezierTo = AABezierBy.subclass({
/** @lends Animation.AABezierTo.prototype */
    classname: 'AABezierTo',
	/**
	 * @class An action that moves a node on a bezier curve to a location.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var bezier = new Animation.AABezier();
	 * bezier.controlPoint1.setAll(300,200);
	 * bezier.controlPoint2.setAll(50,350);
	 * bezier.endPosition.setAll(75,400);
	 * var bezierTo = new Animation.AABezierTo(bezier,3.0);
	 * node.runAction(bezierTo);
	 *
	 * @param {AABezier.Class} bezier The bezier values for the curve.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Animation.AABezierBy
	 */
    initialize: function(bezier, duration) { 
		this.startPosition = new Core.Point(0,0);
		this.endPosition = bezier.endPosition.clone();
		this.bezier = bezier;
		this.bezier2 = bezier.clone(); 
		this.elapsed = 0;
		this.duration = duration * 1000;
	},
	
	clone: function() {
		return new AABezierTo(this.bezier.clone(), this.duration/1000);
	},
	
	/**
	 * @private
	 */
	startAction: function(node) {
		this.elapsed = 0;
		this.startPosition = node.getPosition().clone();
		this.bezier2.controlPoint1.setAll(this.bezier2.controlPoint1.getX() - this.startPosition.getX(), this.bezier2.controlPoint1.getY() - this.startPosition.getY());
		this.bezier2.controlPoint2.setAll(this.bezier2.controlPoint2.getX() - this.startPosition.getX(), this.bezier2.controlPoint2.getY() - this.startPosition.getY());
		this.bezier2.endPosition.setAll(this.bezier2.endPosition.getX() - this.startPosition.getX(), this.bezier2.endPosition.getY() - this.startPosition.getY());
	},
});


var AASequence = exports.AASequence = Core.Class.subclass({
/** @lends Animation.AASequence.prototype */
    classname: 'AASequence',
	/**
	 * @class An action that runs other actions sequentially.
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fadein = new Animation.AAFadeIn(0.5);
	 * var fadeout = new Animation.AAFadeOut(0.5);
	 * var pause = new Animation.AADelayTime(2.0);
	 * var sequence = new Animation.AASequence(fadeout, pause, fadein);
	 * node.runAction(sequence);
	 *
	 * @param {Core.Class} array Can pass as many actions as needed in the parameters.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function()
    {
		this.sequence = new Array();
		this.step = 0;
		this.paused = false;
		for (var i=0; i < arguments.length; i++) {
			this.sequence.push(arguments[i]);
		}
    },
	
	/** 
     * Starts the action
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	startAction: function(node) {
		this.step = 0;
		this.paused = false;
		if (this.sequence.length > 0) {
			this.sequence[0].startAction(node);
		}
	},
	
	/** 
     * Moves to the next action in the sequence
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	nextAction: function(node) {
		if (this.sequence.length > this.step) {
			this.sequence[this.step].startAction(node);
		}
	},
	
	/** 
     * Method to be performed on every tick
     * @param {Float} t The time between the last tick interval (in miliseconds)
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	update: function(t, node) {
		if (!this.isDone() && !this.paused) {
			if (this.sequence[this.step].isDone()) {
				this.step++;
				this.nextAction(node);
			} else {
				this.sequence[this.step].update(t,node);
			}
		}
	},
	
	/**
	 * Pauses or unpauses the sequence
	 * @param {Boolean} paused
	 */
	setPaused: function(paused) {
		this.paused = paused;
	},
	
	clone: function() {
		var newSequence = new AASequence();
		for (var i=0; i < this.sequence.length; i++) {
			newSequence.sequence.push(this.sequence[i].clone());
		}
		return newSequence;
	},
	
	/** 
     * Checks to see if the action is completed
     * @param {AANode.Class} node The node to run the action on
     * @returns {Boolean} The action finished executing
     */
	isDone: function() {
		return this.step >= this.sequence.length;
	},
});

var AASpawn = exports.AASpawn = Core.Class.subclass({
/** @lends Animation.AASpawn.prototype */
    classname: 'AASpawn',
	/**
	 * @class An action that can run multiple actions simultaneously
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var moveto = new Animation.AAMoveTo(new Core.Point(100,200), 2.0);
	 * var scale = new Animation.AAScaleTo(new Core.Vector(0.5,0.5), 2.0);
	 * var spawn = new Animation.AASpawn(moveto, scale);
	 * node.runAction(spawn);
	 *
	 * @param {Core.Vector} scale The size to scale to.
	 * @param {Float} duration The duration of the action.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 */
    initialize: function() {
		this.actions = new Array();
		for (var i=0; i < arguments.length; i++) {
			this.actions.push(arguments[i]);
		}
    },
	
	/**
	 * @private
	 */
	startAction: function(node) {
		for (var i=0; i < this.actions.length; i++) {
			this.actions[i].startAction(node);
		}
	},
	
	/**
	 * @private
	 */
	update: function(t, node) {
		for (var i=0; i < this.actions.length; i++) {
			this.actions[i].update(t, node);
		}
	},
	
	clone: function() {
		var newSpawn = new AASpawn();
		for (var i=0; i < this.actions.length; i++) {
			newSpawn.actions.push(this.actions[i].clone());
		}
		return newSpawn;
	},
	
	isDone: function() {
		for (var i=0; i < this.actions.length; i++) {
			if (!this.actions[i].isDone()) return false;
		}
		return true;
	},
});


var AACallbackAction = exports.AACallbackAction = Core.Class.subclass({
/** @lends Animation.AACallbackAction.prototype */
	classname: 'AACallbackAction',
	/**
	 * @class A class with an action and a callback
	 *
	 * @param {AAintervalAction.Class} action The action to be ran
	 * @param {Function} callback The callback after the action is ran
	 * @constructs The default constructor.
	 * @augments Core.Class
	 * @see AAIntervalAction#AACallbackActionQueue
	 */
    initialize: function(action, callback)
    {
		this.action = action;
		this.callback = callback;
    },
	
	clone: function() {
		return new AACallbackAction(this.action.clone(), this.callback);
	},
}); 

var AACallbackActionQueue = exports.AACallbackActionQueue = Core.Class.subclass({
/** @lends Animation.AACallbackActionQueue.prototype */ 
    classname: 'AACallbackActionQueue',
	/**
	 * @class An action that runs other actions sequentially and performs callbacks after
	 * each completed action. This action also doesn't get removed from the AAActionManager
	 * when all actions are completed. You will need to manually remove it when it is no longer
	 * being used. 
	 * Initialize with AACallbackAction class 
	 *  
	 * @example
	 * var node = new Animation.AANode();
	 * var fadeout = new Animation.AAFadeOut(0.5);
	 * var callbackAction = new Animation.AACallbackAction(fadeout, function(param) { alert('abc'); });
	 * var callbackQueue = new Animation.AACallbackActionQueue(callbackAction);
	 * node.runAction(callbackQueue);
	 *
	 * @param {Core.Class} array Can pass as many actions as needed in the parameters.
	 * @constructs The default constructor.
	 * @augments Core.Class
	 * @see AAIntervalAction#AACallbackAction
	 */
    initialize: function()
    {
		this.sequence = new Array();
		this.paused = false;
		this.kill = false;
		for (var i=0; i < arguments.length; i++) {
			this.sequence.push(arguments[i]);
		}
    },
	
	/** 
     * Starts the action
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	startAction: function(node) {
		this.node = node;
		this.paused = false;
		if (this.sequence.length > 0) {
			this.sequence[0].action.startAction(node);
		}
	},
	
	/** 
     * Moves to the next action in the sequence
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	nextAction: function(node) {
		if (this.sequence.length > 0) {
			this.sequence[0].action.startAction(node);
		}
	},
	
	/**
	 * Adds a new action to the sequence. Adds action to the end of the queue if it's currently running,
	 * otherwise it just executes the action.
	 * Use class AACallbackAction
	 * @param {Core.Classs} action The action to be added to the end of the sequence.
	 */
	addCallbackAction: function(callbackaction) {
		this.sequence.push(callbackaction);
		if (this.sequence.length <= 1) {
			this.nextAction(this.node);
		}
	},
	
	/** 
     * Method to be performed on every tick. If an action is finished, execute the callback.
     * @param {Float} t The time between the last tick interval (in miliseconds)
     * @param {AANode.Class} node The node to run the action on
     * @private
     */
	update: function(t, node) {
		if (this.sequence.length > 0 && !this.paused) {
			if (this.sequence[0].action.isDone()) {
				if (typeof this.sequence[0].callback == 'function') this.sequence[0].callback();
				this.sequence.shift();
				this.nextAction(node);
			} else {
				this.sequence[0].action.update(t,node);
			}
		}
	},
	
	/**
	 * Pauses or unpauses the sequence
	 * @param {Boolean} paused
	 */
	setPaused: function(paused) {
		this.paused = paused;
	},
	
	/**
	 * Removes the action from the AAActionManager
	 */
	destroy: function() {
		this.kill = true;
	},
	
	clone: function() {
		var newQueue = new AACallbackActionQueue(); 
		for (var i=0; i < this.sequence.length; i++) {
			newQueue.sequence.push(this.sequence[i].clone());
		}
		return newQueue;
	},
	
	/** 
     * Method to be performed on every tick
     */
	isDone: function() {
		return this.kill;
	},
});